﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace AleaBelli.Core.Data
{
    public class ReferenceData
    {
        private static readonly Lazy<ReferenceData> lazy = new Lazy<ReferenceData>(() => new ReferenceData());

        public static ReferenceData Instance { get { return lazy.Value; } }

        private Dictionary<int, Nation> nations = new Dictionary<int, Nation>();
        private Dictionary<int, Template> templates = new Dictionary<int, Template>();

        private Creator creator = new Creator();

        private ReferenceData()
        {
            LoadReferenceData();
        }

        private void LoadReferenceData()
        {
            XDocument doc = XDocument.Load("Data\\refdata.xml");
            LoadNations(doc);
            LoadTemplates(doc);
        }

        private void LoadNations(XDocument doc)
        {
            IEnumerable<Nation> nationsList =
                 from r in doc.Descendants("Nation")
                 select new Nation
                 {
                     Id = int.Parse(r.Attribute("id").Value),
                     Name = r.Attribute("name").Value
                 };
            foreach (Nation n in nationsList)
            {
                nations[n.Id] = n;
            }

        }

        /// <summary>
        /// Template definition
        ///    id =
        ///    nationId =
        ///    name =
        ///    type = Soft | Hard 
        ///    softAttack =
        ///    softDefence =
        ///     maxStrength="100" maxOrganization="100"
        /// ="100" />
        /// 
        /// </summary>
        /// <param name="doc"></param>
        private void LoadTemplates(XDocument doc)
        {
            IEnumerable<Template> list =
                 from e in doc.Descendants("Template")
                 select new Template
                 {
                     NationId = SafeInt(e, "nationId"),
                     Id = SafeInt(e, "id"),
                     SoftAttack = SafeInt(e, "softAttack"),
                     SoftDefence = SafeInt(e, "softDefence"),
                     MaxStrength = SafeInt(e, "maxStrength"),
                     MaxOrganization = SafeInt(e, "maxOrganization"),
                     UnitType = SafeUnitType(e, "type"),
                     UnitPosition = SafeUnitPosition(e, "position"),
                     UnitSize = SafeUnitSize(e, "size"),
                     UnitGrade = SafeUnitGrade(e, "grade"),
                     Name = SafeString(e, "name")
                 };
            foreach (Template i in list)
            {
                templates[i.Id] = i;
            }
        }

        private UnitSize SafeUnitSize(XElement e, string name)
        {
            int size = SafeInt(e, name);
            if (size == 0)
            {
                // TODO Add new 'unknown' enum ?
                return UnitSize.Battalion;
            }
            return (UnitSize)size;
        }

        private UnitType SafeUnitType(XElement e, string name)
        {
            string value = SafeString(e, name);
            if (string.IsNullOrEmpty(value))
            {
                // TODO Add new 'unknown' enum ?
                return UnitType.Soft;
            }
            return (UnitType)Enum.Parse(typeof(UnitType), value);
        }

        private UnitGrade SafeUnitGrade(XElement e, string name)
        {
            string value = SafeString(e, name);
            if (string.IsNullOrEmpty(value))
            {
                // TODO Add new 'unknown' enum ?
                return UnitGrade.Poor;
            }
            return (UnitGrade)Enum.Parse(typeof(UnitGrade), value);
        }

        private UnitPosition SafeUnitPosition(XElement e, string name)
        {
            string value = SafeString(e, name);
            if (string.IsNullOrEmpty(value))
            {
                // TODO Add new 'unknown' enum ?
                return UnitPosition.Line;
            }
            return (UnitPosition)Enum.Parse(typeof(UnitPosition), value);
        }

        private string SafeString(XElement e, string name)
        {
            if (e == null)
            {
                return "";
            }
            XAttribute a = e.Attribute(name);
            if (a == null)
            {
                return "";
            }
            string value = a.Value;
            if (string.IsNullOrEmpty(value))
            {
                return "";
            }
            return value;
        }

        private int SafeInt(XElement e, string name)
        {
            if (e == null) 
            {
                return 0;
            }
            XAttribute a = e.Attribute(name);
            if (a == null)
            {
                return 0;
            }
            string value = a.Value;
            if (string.IsNullOrEmpty(value))
            {
                return 0;
            }
            return int.Parse(value);
        }

        /*
        private void LoadBattalionTemplates(XDocument doc)
        {
            IEnumerable<BattalionTemplate> list =
                 from e in doc.Descendants("Battalion")
                 select new BattalionTemplate
                 {
                     Id = int.Parse(e.Attribute("id").Value),
                     SoftEffectivness = int.Parse(e.Attribute("softAttack").Value),
                     Name = e.Attribute("name").Value
                 };
            foreach (BattalionTemplate i in list)
            {
                battalionTemplates[i.Id] = i;
            }

        }

        private void LoadUnitTemplates(XDocument doc)
        {
            IEnumerable<Template> list =
                 from e in doc.Descendants("Unit")
                 select new Template
                 {
                     Id = int.Parse(e.Attribute("id").Value),
                     Name = e.Attribute("name").Value
                 };
            foreach (Template i in list)
            {
                unitTemplates[i.Id] = i;
            }
        }
        */
        public Nation GetNation(int nationId)
        {
            return nations[nationId];
        }

        public IEnumerable<Nation> GetAllNations()
        {
            return from n in nations
                   select n.Value;
        }

        public Template GetTemplate(int templateId)
        {
            return templates[templateId];
        }
    }
}
